home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2.0 - Programmer's Utilities Power Pack / Delphi 2.0 Programmer's Utilities Power Pack.iso / s_to_z / tblinfo / tblinfo.txt < prev   
Encoding:
Text File  |  1996-09-15  |  12.4 KB  |  295 lines

  1.  
  2.  
  3. About the TblInfoDlg Component...
  4.  
  5. The Delphi Component Writer's Guide recommends that you take 
  6. frequently used dialogs and make them into components and 
  7. that you create a 'wrapper' unit so that the form and it's
  8. associated resources are only loaded into memory when they're
  9. needed. They even provide an example with an 'About' dialog.
  10. Fine as far as it goes, but most dialogs are a little more
  11. complex. The TblInfoDlg component is a multi-page dialog that gives
  12. a user lots of information about a Paradox, DBase or ODBC table.
  13.  
  14. This example (of sorts) consists of :
  15.  
  16.     The files for the wrapper unit: 
  17.     TBLINFO.PAS
  18.     TBLINFO.DCU
  19.     TBLINFO.DCR
  20.  
  21.     The files for the TblInfoDlg dialog:
  22.     TBLDLG.PAS
  23.     TDLIDLG.DCU
  24.     TBLDLG.DFM
  25.  
  26.     The files for the sample program:
  27.     DBIT.DPR
  28.     DBIT.OPT
  29.     DBIT.RES
  30.     DBITEST.DCU
  31.     DBITEST.DFM
  32.     DBITEST.PAS
  33.  
  34. To use all this, you have to install the TblInfoDlg component by
  35. adding tblinfo.pas to the component palette, where it will show up
  36. on the Data Controls page. Once this is done, the Dbit.dpr project 
  37. file can be opened and run. What you'll see is a small form with four 
  38. buttons-one pops up a File Open dialog that allows you to open a
  39. table, and the second one pops up the TblInfoDlg dialog with information
  40. about the aforementioned table, the third one closes the table and the
  41. fourth one closes the sample program. We at SJHDesign have found this 
  42. component quite handy, it's been pretty well tested and is currently 
  43. hard at work in real world applications at two client sites, so the 
  44. code is(to our knowledge) solid.
  45.  
  46.  
  47. Using the TblInfoDlg component in your applications:
  48. _________________________________________________
  49.  
  50. All you have to do to use this component is supply it with a
  51. TTable component. This can be done at design time, by using the
  52. Object Inspector to put the fully qualified filename of a DBase,
  53. Paradox or ODBC table(which must already be opened before you
  54. call the TblInfoDlg object) in the TABLE property field or at run 
  55. time with code similar to this in your application:
  56.  
  57.           Table1 : TTable;
  58.           TblInfoDlg1 : TTblInfoDlg;
  59.  
  60.           Table1.open;
  61.       {Note that the table MUST be open before
  62.        calling the TblInfoDlg object} 
  63.  
  64.       TblInfoDlg1.table := table1;
  65.         TblInfoDlg1.execute;
  66.  
  67. If the TTable object you pass to TblInfoDlg is invalid or inactive, an
  68. error message pops up and it cleans up and terminates. Additional 
  69. properties allow easy runtime access to the dialog's font, color and 
  70. caption. Any change made in the font or color is also made for all of 
  71. the dialog's subcomponents.
  72.  
  73.  
  74. Why put form properties in a wrapper unit?
  75. __________________________________________________________
  76.  
  77. Good question. Delphi's architecture makes it very easy for the
  78. component user to change the properties of the 'wrapped' form
  79. (in this case, Tbldlg.pas)visually in the Object Inspector. That's
  80. great for design time, but some properties are useful to have around
  81. at run time.  Since the TblDlg form is owned by the TblInfo unit,
  82. the user can access it's properties at runtime, but it would take 
  83. some classically convoluted OOP code to do it. For example, by placing 
  84. all the code needed to change the fonts of TblDlg and it's subcomponents 
  85. into the wrapper unit, it takes the component user one line of code to do 
  86. what otherwise would have taken 20 or 30 lines(this is also the reasoning 
  87. behind the Parentxxx properties in Borland's components). In general, it
  88. helps to know how to add properties to a given component-non-visual 
  89. components like TblInfoDlg(descended from TComponent) don't inherit 
  90. very much in the way of properties. This listing shows all the code 
  91. needed to let the user set TblDlg's font through the wrapper:
  92.  
  93.     interface 
  94.  
  95.     type
  96.       
  97.       private
  98.              fFont: TFont;
  99.              procedure DlgFont(value : TFont);
  100.  
  101.       published
  102.              property Font : TFont read FFont write DlgFont;
  103.               {you don't specify a default value here-the program 
  104.            will use either the font defined in object inspector 
  105.            or the system default font}
  106.  
  107.           var
  108.             MultPageDlg: TMultPageDlg;{the TblInfoDlg dialog form}
  109.  
  110.          implementation
  111.  
  112.          constructor TTblInfoDlg.Create(AOwner: TComponent);
  113.          begin
  114.            inherited Create(AOwner);
  115.            fFont := TFont.Create; 
  116.            {the font and all other added property fields are
  117.                 initialized to default values}
  118.  
  119.  
  120.          function TTblInfoDlg.Execute : Boolean;
  121.          begin
  122.            MultPageDlg := TMultPageDlg.Create(Application);
  123.            MultPageDlg.Font := fFont;
  124.        {this initializies the TblInfoDlg dialog and sets it's font
  125.             to the default value}
  126.  
  127.      procedure tTblInfoDlg.DlgFont(value : TFont);
  128.      begin
  129.          if FFont <> Value then
  130.          begin
  131.              FFont.Assign(Value);
  132.         {here is where the wrapper unit changes the value in the 
  133.            font property field when the user changes the value in the
  134.             object inspector} 
  135.  
  136. Note that when you install the component, it defaults to whatever your
  137. system font is. Everybody's tastes are different, but I think it looks
  138. best using MsSanSerif, 8, Bold. You can adjust this in TTblInfoDlg's
  139. Font property at design time.
  140.  
  141. The pattern is pretty much the same for the other properties depending
  142. on the property's data type.
  143.  
  144.  
  145. Why use BDE in Delpi Applications?
  146. ___________________________________
  147.  
  148. With the exception of a few omissions , Delphi's implementation of BDE
  149. will serve you pretty well. If however, you are developing anything out
  150. of the ordinary, you'll eventually have to use BDE functions to fill in 
  151. the gaps in Delphi's simplified(but very neatly encapsulated) version of 
  152. BDE. To use BDE directly, you have to include DBIPROCS and DBITYPES in
  153. your USES declaration.
  154.  
  155. Then there's the size issue-Delphi programs can get huge(I shouldn't
  156. talk..using the TblInfoDlg component will add about 80k to a program, 
  157. big even by Delphi standards). Judicious use of BDE calls instead of 
  158. adding and creating more components can substantially cut down on the 
  159. size, load time and memory overhead of your exe's.
  160.  
  161. Dbbrowse(in delphi\demos\db\tools) is the only Delphi demo program with
  162. direct calls to BDE. Borland takes the approach of creating 4 components
  163. to handle the 4 BDE calls used in this program. While this approach works 
  164. fine, it's not mandatory (the advantages to this approach are simplicity 
  165. and the fact that Delphi handles most exceptions). Calling BDE functions
  166. from your program instead of componentizing them is a little harder, but
  167. could result in significant gains in speed and smaller exe size. With good
  168. error checking, any BDE function will work safely in a Delphi program, and a 
  169. number of them are used in the procedures GetTableDate_Size, DisplayFields
  170. and Display Indexes. With the exception of GetTableDate_Size, the same 
  171. information could have been gathered from Delphi's component methods and 
  172. data structures, but the required overhead would be much greater considering 
  173. that this is just a dialog that displays the stuff and disappears. In the
  174. case of GetTableDate_Size, the choice is between using a specialized BDE 
  175. function like dbiOpenTableList(which walks the BDE handle chain to get 
  176. physical file information that was stored at the time the file was opened)
  177. or using the runtime library routines FileSize and FileGetDate(which close 
  178. and reset the file and could wreak all sorts of havoc on the Delphi data 
  179. controls that are linked to the table). The former just seems simpler and 
  180. safer.
  181.  
  182. BDE Error Checking
  183. ___________________
  184.  
  185. Anyone who has had the experience of watching their Database program set off
  186. a long chain of excepetions and crash has probably learned this the hard way
  187. and can skip this part. Those who are new to BDE, though, might take some well
  188. meaning advice. Exception handling is an area where Delphi truly shines, making
  189. the Visual Basics and PowerBuilders of the world look feeble by comparison. When
  190. you use a Data Component, you get the benefit of Delphi's strong exception and 
  191. error handling, but if you use direct BDE calls, you have to provide your own.
  192.  
  193. Let's look at Dbbrowse again-the bdetable.pas unit(which contains the 3 BDE 
  194. calls) wraps the calls in a CHECK routine which uses BDE's error stack to
  195. return the success or failure of direct BDE calls. While this is adequate
  196. for debugging and development, all you're doing here is getting information
  197. on whether your call went ok or why it failed. If the call DID fail, CHECK
  198. returns the error value and the program merrily goes on to the next call.
  199. If for example, the failed BDE call was supposed to return a cursor handle
  200. (hdbicur), the subsequent calls which access the data fields pointed to by 
  201. this cursor will return a nil pointer(if you're lucky) or fail. To see this 
  202. in action, load the Dbbrowse project(you have to install the three components
  203. in bdetable.pas first) and use the IDE Run command to run the Dbbrowse program.
  204. If you choose the View Table command without having the outline cursor on a
  205. table, you'll see a whole chain of error messages and then a GP fault as the
  206. BDE functions repeatedly try to access data in a nonexistent table.
  207.  
  208. What we're trying to say here is that there are many cases whre your function 
  209. that uses BDE calls must clean up and bail out if the call wasn't successful.
  210. Calls which return a handle of any type (like DbiOpenTableList, DbiOpenIndexList,
  211. or DbiOpenFieldList) fall into this category. Calls which return pointers to
  212. BDE data structures(like dbiGetCursorProps) can also be dangerous if execution
  213. continues after they fail. Table and field level calls like DBIGetNext Record
  214. or DBIGetField will simply return nil pointers or empty buffers if they fail-
  215. this alone won't cause your program to crash, but it won't endear you to the
  216. users of your program when they see garbage or blank fields instead of data.
  217.  
  218. This is the reason for the paranoid-type code in DisplayIndexes, DisplayFields
  219. and GetTableDate_Size. To use BDE's error stack, you need to include DBIERRS in
  220. your uses clause. All BDE functions return DBIERR_NONE if successful and the
  221. three functions just mentioned show how to utilize this return value. Here's
  222. an example:
  223.  
  224. var
  225.   hCur : hDBICur;{BDE Cursor handle}
  226.   name : array[0..80]of Char;{names passed to BDE functions can't be strings}
  227.   recbuf :pbyte;{record buffer}
  228.   tblprops :curprops;{table properties struct}
  229.  
  230. begin
  231.   recs := table.FieldCount-1;
  232.   strPcopy(name,Table.TableName);
  233.  
  234.   {get a cursor handle to the field list table}
  235.   if DbiOpenFieldList(table.DBHandle, name, nil, False, hCur) = DBIERR_NONE then
  236.   {call was successful-continue}
  237.  
  238.   begin 
  239.     if dbiGetCursorProps(hCur,tblprops)= DBIERR_NONE then
  240.     begin
  241.       {call was successful-continue}
  242.  
  243.       dbiSetToBegin(hCur);
  244.       for i := 0 to recs do
  245.       begin
  246.       {$I+}
  247.       {use Delphi's exception handling routine to handle failed allocations gracefully}
  248.       try 
  249.         GetMem(RecBuf, tblProps.iRecBufSize*sizeof(BYTE));
  250.       except
  251.         on EOutOfMemory do
  252.         {bail out and clean up}
  253.     begin
  254.           DbiCloseCursor(hCur);
  255.           {show error message here if you want}
  256.           exit;
  257.         end;
  258.       {$I-}
  259.       end;
  260.         {various record and field level calls here}     
  261.         if recbuf <> nil then freemem(recbuf, tblprops.iRecBufSize * sizeof(BYTE));
  262.       end;
  263.       DbiCloseCursor(hCur);
  264.     end
  265.     else {call to dbiGetCursorProps failed-bail out and clean up}
  266.     begin
  267.       DbiCloseCursor(hCur);
  268.       {show error message}
  269.     end;
  270.   end
  271.   else ;{call to DbiOpenFieldList failed-show error message here}
  272.  
  273. Borland's advice that you get the BDE devleloper's guide if you want to do
  274. this kind of stuff is very well taken. Contact them for info if you want this-
  275. I've found the Borland people on their various CIS development forums to be
  276. quite helpful.
  277.  
  278. Anyway, I've said enough-you're better off looking at the code. Feel free to 
  279. use this component in your programs or do whatever you like with it.
  280. Comments, improvements, opposing points of view, questions and the like are
  281. always welcome.
  282.  
  283.  
  284. Scott Hanrahan
  285. SJHDesign, INC
  286. CIS 70144,3033
  287.  
  288.  
  289. PS : The lawyer said I should always put in a disclaimer, even for sample code
  290. uploaded for the edification of others. This is example code for instructional
  291. purposes only and we do not make any warranties as to it's quality or suitability 
  292. for your purposes-that's up to you to determine. 
  293.  
  294. Enjoy!
  295.